/**
 * 
 */
package Client.Model;

import java.io.IOException;

import javax.swing.JOptionPane;

import logic.Board;
import logic.ChatMessage;
import logic.OnlinePlayer;
import logic.PlayRequest;

import communication.ConnectResponse;
import communication.GameMessage;
import communication.ServerMessage;
import communication.ServerMessageID;

/**
 * @author Rodrigo
 *
 */
public class ReceiveMessages extends Thread{

	private GameModel model;
	private volatile boolean stop = false;
	
	private ServerMessageID smid;
	private ServerMessage srvMsg;
	private GameMessage gameMsg;
	private ConnectResponse connResponse;
	
	public ReceiveMessages(GameModel m) {
				
		this.model = m;
		
	}
	 
	public void requestStop() {
		    stop = true;
	}	
	
	
	@Override
	public void run() {


		while(!stop){ 

			try {

				//Read the object that identifies the type of message received
				smid = (ServerMessageID) model.getIn().readObject();

				switch(smid.getType()){

				case ServerMessageID.SERVER_MESSAGE:

					srvMsg = (ServerMessage) model.getIn().readObject();
					handleServerMessage(srvMsg);

					break;

				case ServerMessageID.GAME_MESSAGE:

					gameMsg = (GameMessage) model.getIn().readObject();
					handleGameMessage(gameMsg);

					break;

				case ServerMessageID.CONNECT_RESPONSE:

					connResponse = (ConnectResponse) model.getIn().readObject();
					handleConnectResponse(connResponse);

					break;


				}


			}catch(IOException ex){
				//ex.printStackTrace();
				
				if (stop==false){
					model.getNotifications().add(new Notification(Notification.SERVER_OFFLINE));
					MsgBox("Server offline!");
					stop = true;
				}
				
				model.setView(GameModel.VIEW_INITIAL);
				model.update();

			}catch(ClassNotFoundException ex){
				ex.printStackTrace();

			}catch (Exception ex){ 
				ex.printStackTrace();
			}

		} //END While (!stop)

		System.out.println("Stopped!");
	}

	//Note: it isn't suposed to receive any request from this type in this thread
	
	private void handleConnectResponse(ConnectResponse rsp) {
		
		switch(rsp.getResponse()){
		
		case ConnectResponse.RESP_LOGIN_ALREADY_LOGGED:
			
			break;
		
		case ConnectResponse.RESP_LOGIN_FULL:
			
			break;
			
		case ConnectResponse.RESP_LOGIN_INVALID:
			
			break;
			
		case ConnectResponse.RESP_LOGIN_OK:
			
			break;
		
		case ConnectResponse.RESP_REGISTER_ERROR:
			
			break;
			
		case ConnectResponse.RESP_REGISTER_OK:
			
			break;
			
		case ConnectResponse.RESP_REGISTER_USERNAME_ALREADY_EXISTS:

			break;
		
		
		
		}
		
	}

	private void handleGameMessage(GameMessage gameMsg) {
		
		switch(gameMsg.getType()){
		
		case GameMessage.GAME_DISCONNECTED:
			
			model.getNotifications().add(new Notification(Notification.GAME_DISCONNECTED));
			model.setView(GameModel.VIEW_CONNECTED);
			MsgBox("Game disconnected!");
			
			model.update();
			
			break;

		case GameMessage.GAME_MSG_RECEIVED:
	
			break;

		case GameMessage.GAME_START:
			
			if (gameMsg.isFirstToPlay())
				model.setMyTurn(true);
			else
				model.setMyTurn(false);
			
			model.setGamestate(GameModel.STATE_PLAYING);
						
			model.update();
			
			break;

		case GameMessage.GAME_OVER:

			model.setGamestate(GameModel.STATE_FINISHED);
			model.update();
			
			MsgBox("You Lost the Game :( ");
			
			break;

		case GameMessage.GAME_WIN:
			
			model.setGamestate(GameModel.STATE_FINISHED);
			model.update();

			MsgBox("You Won the Game!!");
			
			break;
			
		case GameMessage.GAME_ENEMY_MOVE:

			System.out.println("ENEMY MOVE");
			
			model.getBoard().shotAt(gameMsg.getLine(), gameMsg.getColumn());
			model.setMyTurn(true);
			
			model.update();
			
			break;

		case GameMessage.GAME_MY_MOVE_RES:
			
			System.out.println("MY MOVE RES");
			
			if (gameMsg.isShipDestroyed())
				model.getEnemyBoard().getShips().add(gameMsg.getShip());

			if (gameMsg.isOnShip())
				model.getEnemyBoard().setStateAt(gameMsg.getLine(), gameMsg.getColumn(), Board.BOARD_SHOT_IN_SHIP);
			else
				model.getEnemyBoard().setStateAt(gameMsg.getLine(), gameMsg.getColumn(), Board.BOARD_SHOT_IN_WATER);
			
			model.update();

			break;
			
		case GameMessage.GAME_ENEMY_CONFIGURED:
			
			model.setEnemyBoardConfigured(true);
			model.update();
						
			break;
			
		case GameMessage.GAME_CONFIG_OK:
			
			model.setBoardConfigured(true);
			model.update();
			
			break;
			
		case GameMessage.GAME_QUIT:
			
			model.setGamestate(GameModel.STATE_FINISHED);
			model.update();
			
			MsgBox("Enemy Quit the game!");


		}
		
	}


	private void handleServerMessage(ServerMessage msg) {
		
		switch(msg.getType()){

		case ServerMessage.MSG_UPDATE_ALL:
		    //actualiza os utilizadores quando o utilizador se liga

			model.setOnlinePlayers(msg.getOnlinePlayers());
			model.update();

			break;

		case ServerMessage.MSG_CHAT_MSG:
			//mensagem de Chat recebida
			
			model.getMessages().add(new ChatMessage(msg.getUsername(), msg.getMsg()));
			
			model.update();
			
			break;
		
		case ServerMessage.MSG_INVITATION_ACCEPTED:
			//alguém aceitou um convite enviado por este user
			
			model.getNotifications().add(new Notification(Notification.INVITATION_ACCEPTED));
			model.update();
			
			MsgBox("Invitation accepted by: " + msg.getUsername());
			
			break;
			
			
		case ServerMessage.MSG_PLAY_GAME:
			//modo de jogo
			
			synchronized (model) {
				model.setView(GameModel.VIEW_GAME);
				model.setEnemy(msg.getUsername());
				model.setGamestate(GameModel.STATE_SETTING);
				
				model.setBoard(Board.getDefaultBoard());
				model.setEnemyBoard(Board.getDefaultEnemyBoard());
			}
			
			model.update();

						
			break;
			
			
		case ServerMessage.MSG_PLAYER_IN:
			//Utilizador ligou-se
			
			model.getNotifications().add(new Notification(Notification.USER_IN));
			
			OnlinePlayer p = new OnlinePlayer();
			p.username = msg.getUsername();
			
			model.getOnlinePlayers().add(p);
			model.update();						
			
			break;
			
		case ServerMessage.MSG_PLAYER_OUT:
			//Utilizador desligou-se
			
			model.getNotifications().add(new Notification(Notification.USER_OUT));
			
			for (OnlinePlayer op : model.getOnlinePlayers())
				if (op.username.equals(msg.getUsername())){
					model.getOnlinePlayers().remove(op);
					return;
				}
			
			model.update();
			
			break;
			
		case ServerMessage.MSG_NEW_INVITATION:
			//recebido novo convite de jogo
			
			model.getNotifications().add(new Notification(Notification.INVITATION_RECEIVED, msg.getUsername()));
			model.getPlayRequests().add(new PlayRequest(msg.getUsername(), model.getUsername()));
			
			model.update();
			
			break;
		
		
		case ServerMessage.MSG_INVITATION_REJECTED:
			//um convite enviado por este utilizador foi rejeitado
			
			model.getNotifications().add(new Notification(Notification.INVITATION_REJECTED, msg.getUsername()));
			model.deletePlayRequestTo(msg.getUsername());
			
			MsgBox("Invitation rejected by: " + msg.getUsername());
			
			model.update();
			
			break;

		case ServerMessage.MSG_INVITATION_CANCELED:
			//um convite enviado para este utilizador foi cancelado pelo seu autor
			
			model.getNotifications().add(new Notification(Notification.INVITATION_REJECTED, msg.getUsername()));
			
			model.deletePlayRequestFrom(msg.getUsername());
			
			model.update();
			
			break;

		}
		
		
	}
	
	
	private void MsgBox(String str){
		
		JOptionPane.showMessageDialog(null, str);
	}
	

	
}
